﻿#include "Subsystem/ProtocolSubsystem.h"
#include "Http.h"
#include "Misc/Paths.h"
#include "HAL/PlatformFilemanager.h"
#include "GenericPlatform/GenericPlatformFile.h"

void UProtocolSubsystem::Initialize(FSubsystemCollectionBase& Collection)
{
	Super::Initialize(Collection);
}

bool UProtocolSubsystem::DownloadFile(const FString& URL, const FString& SavePath)
{
	if (URL.IsEmpty() || SavePath.IsEmpty())
	{
		return false;
	}
	FileURL = URL;
	FileSavePath = SavePath;
	TSharedRef<IHttpRequest,ESPMode::ThreadSafe> HttpRequest = HTTPRequest(FileURL, "GET");
	HttpRequest->OnRequestProgress().BindUObject(this, &UProtocolSubsystem::OnFileDownloadProgress);
	HttpRequest->OnProcessRequestComplete().BindUObject(this, &UProtocolSubsystem::OnFileDownloadReady);
	HttpRequest->ProcessRequest();
	return true;
}

bool UProtocolSubsystem::HTTPPostMessage(const FString& URL, const FString& PostData)
{
	// FString PostData;
	// TSharedRef<TJsonWriter<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>> JsonWriter = TJsonWriterFactory<TCHAR, TPrettyJsonPrintPolicy<TCHAR>>::Create(&Serverdata);
	// JsonWriter->WriteObjectStart();
	// JsonWriter->WriteValue("id", id);
	// JsonWriter->WriteObjectEnd();
	// JsonWriter->Close();
	if (URL.IsEmpty())
	{
		return false;
	}
	FString Header = "{\"Content-Type\":\"application/json;charset=UTF-8\",\"Totoro-Token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MjcwODk5NTZ9.0Z3QGWmVZUpBjZB23sRyq2Ao_mln19DWrq3qewvtlbU\"}";
	TSharedRef<IHttpRequest,ESPMode::ThreadSafe> HttpRequest = HTTPRequest(URL, "POST", Header, PostData);
	// 绑定回调
	HttpRequest->OnProcessRequestComplete().BindUObject(this, &UProtocolSubsystem::OnPostReady);
	// 发送请求
	HttpRequest->ProcessRequest();
	return true;
}

bool UProtocolSubsystem::HTTPGetMessage(const FString& URL)
{
	if (URL.IsEmpty())
	{
		return false;
	}
	TSharedRef<IHttpRequest,ESPMode::ThreadSafe> HttpRequest = HTTPRequest(URL, "GET");
	HttpRequest->OnProcessRequestComplete().BindUObject(this, &UProtocolSubsystem::OnGetReady);
	HttpRequest->ProcessRequest();
	return true;
}

TSharedRef<IHttpRequest,ESPMode::ThreadSafe> UProtocolSubsystem::HTTPRequest(const FString& URL, const FString& Verb, const FString& Header, const FString& Content)
{
	TSharedRef<IHttpRequest,ESPMode::ThreadSafe> HttpRequest = FHttpModule::Get().CreateRequest();
	HttpRequest->SetVerb(Verb.ToUpper());
	HttpRequest->SetURL(URL);
	if (Verb.ToUpper().Equals("POST"))
	{
		FString TempString = Header;
		TSharedRef<TJsonReader<>> Reader = TJsonReaderFactory<>::Create(TempString);
		TSharedPtr<FJsonObject> Object;
		bool bSuccessful = FJsonSerializer::Deserialize(Reader, Object);
		check(bSuccessful);
		check(Object.IsValid());
		for (auto Elem : Object->Values)
		{
			check(Elem.Value && Elem.Value->Type == EJson::String);
			const FString AdditionalHeaderValue = Elem.Value->AsString();
			HttpRequest->AppendToHeader(Elem.Key, AdditionalHeaderValue);
		}
		HttpRequest->SetContentAsString(Content);
	}
	return HttpRequest;
}

void UProtocolSubsystem::OnFileDownloadProgress(FHttpRequestPtr Request, int32 BytesSent, int32 BytesReceived)
{
	const FHttpResponsePtr Response = Request->GetResponse();
	if (Response.IsValid())
	{
		const int32 FullSize = Response->GetContentLength();
		OnProgress.Broadcast(BytesSent, BytesReceived, FullSize);
	}
}

void UProtocolSubsystem::OnFileDownloadReady(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
	Request->OnProcessRequestComplete().Unbind();
	if (Response.IsValid() && EHttpResponseCodes::IsOk(Response->GetResponseCode()) && bWasSuccessful)
	{
		FString Path, Filename, Extension;
		IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
		FPaths::Split(FileSavePath, Path, Filename, Extension);
		if (!PlatformFile.DirectoryExists(*Path))
		{
			if (!PlatformFile.CreateDirectoryTree(*Path))
			{
				OnResult.Broadcast(DirectoryCreationFailed);
				return;
			}
		}
		IFileHandle* FileHandle = PlatformFile.OpenWrite(*FileSavePath);
		if (FileHandle)
		{
			FileHandle->Write(Response->GetContent().GetData(), Response->GetContentLength());
			delete FileHandle;
			OnResult.Broadcast(SuccessDownloading);
		} else
		{
			OnResult.Broadcast(SaveFailed);
		}
	} else
	{
		OnResult.Broadcast(DownloadFailed);
	}
}

void UProtocolSubsystem::OnPostReady(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
	if (Response.IsValid() && bWasSuccessful)
	{
		OnPostResult.Broadcast(Response->GetContentAsString());
	} else
	{
		OnPostResult.Broadcast("");
	}
}

void UProtocolSubsystem::OnGetReady(FHttpRequestPtr Request, FHttpResponsePtr Response, bool bWasSuccessful)
{
	if (Response.IsValid() && bWasSuccessful)
	{
		OnGetResult.Broadcast(Response->GetContentAsString());
	} else
	{
		OnGetResult.Broadcast("");
	}
}
